/*
 * StringType.java
 *
 * Created on July 31, 2007, 7:42 PM
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.variable.types;

import java.util.HashMap;
import tal.drivechain.chain.ChainNode;
import tal.drivechain.matchers.StringMatcher;
import tal.drivechain.matchers.ValueMatcher;
import tal.drivechain.wildcard.Wildcard;
import tal.drivechain.expression.dcExpression;
import tal.drivechain.module.properties.StringParser;
import tal.drivechain.variable.Variable;

/**
 * A DataType class that handles strings
 * Name: "string"
 * Value object: String
 * Value range: A sequence of characters
 * Type code: 7
 * Syntax: string:"<a string>"
 * Can cast from any data type by using its value's toString() method.
 *
 * @author Tal Eisenberg
 */
public final class StringType extends DataType implements IndexableType{
    public StringType() {
        super("string", String.class, 7);
    }

    public Object parseValue(String value) throws IllegalArgumentException {
        StringParser parser = new StringParser();
        HashMap<String, String> attr = new HashMap<String,String>();
        attr.put("require-apostrophes", "true");
        parser.setAttribures(attr, null);
        return parser.parseProperty(value);
    }
    
    @Override
    public Object cast(Object value) throws IllegalArgumentException {
        try {
            return super.cast(value);
        } catch (IllegalArgumentException e) {
            if (value==null) throw e;
            else return value.toString();
        }
    }

    @Override
    public String toString(Object value, ChainNode context) {
        return "'" + value + "'";
    }

    @Override
    public ValueMatcher createValueMatcher() throws IllegalArgumentException {
        return new StringMatcher();
    }

    public Object setByIndex(Object workon, Variable value, dcExpression index, ChainNode context) throws IllegalArgumentException {
        if (!(index.getReturnVarType() instanceof NumberType))
            throw new IllegalArgumentException("Substring index has to be an int expression: " + index);
        
        int idx = (Integer)index.evaluate(context);
        String changeString = (String)value.getInternalValue();
        String sWorkOn = (String)workon;
        if (idx>=sWorkOn.length() || idx<0) 
            throw new IllegalArgumentException("Index out of range: " + idx);
        String newString = sWorkOn.substring(0, idx) + changeString;
        if (newString.length()<sWorkOn.length())
            newString += sWorkOn.substring(newString.length());
        return newString;

    }

    public Variable getByIndex(Wildcard index, Variable from, ChainNode context) throws IllegalArgumentException {
        String workon = (String)from.getInternalValue();
        String product = "";
        for (int i=0; i<workon.length(); i++)
            if (index.matches(i, context)) product += workon.charAt(i);
        return new Variable(from.getName() + "$sub", DataType.STRING, product, true);
    }

    public boolean isNestingAllowed() {
        return false;
    }

    public Object getNextDimension(Object workon, Object modifier, ChainNode context) {
        throw new UnsupportedOperationException("IndexableType.getNextDimension() is not supported for string.");
    }
}
